package design_pattern.study.spring;

import java.lang.reflect.Method;

/**
 * 该类主要是加载类路径下的配置文件，并进行bean对象的创建，主要完成以下功能：
 *
 * * 在构造方法中，创建BeanDefinitionReader对象。
 * * 在构造方法中，调用refresh()方法，用于进行配置文件加载、创建bean对象并存储到容器中。
 * * 重写父接口中的getBean()方法，并实现依赖注入操作。
 * @Author fb_li
 * @Date 2022/6/7 21:18
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation){
        this.configLocation = configLocation;
        super.beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String name) throws Exception {
        Object o = super.singletonObjects.get(name);
        if (o!=null){
            return o;
        }
        BeanDefinitionRegistry registry = super.beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        if(beanDefinition == null) {
            return null;
        }
        //通过反射创建对象
        String className = beanDefinition.getClassName();
        Class<?> aClass = Class.forName(className);
        Object o1 = aClass.newInstance();
        //进行依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getMutablePropertyValues();
        for (PropertyValue propertyValue:propertyValues){
            String propertyName = propertyValue.getName();
            String ref = propertyValue.getRef();
            String value = propertyValue.getValue();
            if (ref!=null && !"".equals(ref)){
                //获取依赖的bean对象
                Object bean = getBean(ref);
                //拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                //获取所有的方法对象
                Method[] methods = aClass.getMethods();
                for (Method method:methods){
                    if (method.equals(methodName)){
                        //执行该set方法，进行依赖注入
                        method.invoke(o1,bean);
                    }
                }
            }
            if (value!=null && "".equals(value)){
                String methodName = StringUtils.getSetterMethodByFieldName(value);
                Method method = aClass.getMethod(methodName, String.class);
                method.invoke(o1,value);
            }
        }

        super.singletonObjects.put(name,o1);
        return o1;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if (bean == null){
            return null;
        }
        //类型强转为clazz类型
        return clazz.cast(bean);
    }
}
